package com.hspedu.spring.hspapplicationcontext;

import com.hspedu.spring.bean.Monster;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: lihaojie
 * @Description:
 * 1、这个程序用于实现Spring的一个简单容器机制
 * 2、后面还会详细的实现
 * 3、这里我们实现如何将beans.xml文件进行解析并生成对应对象放入到容器在中
 * 4、提供一个方法 getBean(String id) 返回对应的对象
 * @DateTime: 2024/1/29 15:14
 **/
public class HspApplicationContext {

    private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();

    // 构造器接收一个容器的配置文件 比如beans.xml 该文件默认在src下
    public HspApplicationContext(String iocBeanXmlPath) throws Exception {
        // 1、得到类加载路径
        String path = this.getClass().getResource("/").getPath();
        // 2、使用dom4j读取 创建saxReader
        SAXReader saxReader = new SAXReader();
        // 3、得到文档对象Document
        Document document = saxReader.read(new File(path + iocBeanXmlPath));
        // 4、得到rootDocument
        Element rootElement = document.getRootElement();
        // 5、得到第一个bean
        Element bean = (Element) rootElement.elements("bean").get(0);
        // 6、把id class 属性 都拿出来
        String id = bean.attributeValue("id");
        String classFullPath = bean.attributeValue("class");
        List<Element> property = bean.elements("property");
        // 直接获取
        Map<String, String> kvs = new HashMap<>();
        for (Element element : property) {
            String name = element.attributeValue("name");
            String value = element.attributeValue("value");
            kvs.put(name, value);
        }
        // 7、使用反射创建对象
        Class<?> aClass = Class.forName(classFullPath);
        // 这里的o对象就是Monster对象
        Monster monster = (Monster)aClass.newInstance();
        // 用反射来赋值
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            if (kvs.containsKey(declaredField.getName())) {
                declaredField.setAccessible(true);
                declaredField.set(monster, kvs.get(declaredField.getName()));
            }
        }
        // 8、放进容器
        singletonObjects.put(id, monster);
    }

    public Object getBean(String id) {
        return singletonObjects.get(id);
    }

}
